package com.plian.system.service.im.impl;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.metadata.fill.FillConfig;
import com.alibaba.excel.write.metadata.fill.FillWrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.plian.Tools.BigDecimalUtil;
import com.plian.Tools.CollectionUtil;
import com.plian.Tools.DateUtil;
import com.plian.Tools.StringPool;
import com.plian.spring.SpringUtil;
import com.plian.system.bean.im.FundProjectExcelBean;
import com.plian.system.constant.im.InvestmentConstant;
import com.plian.system.constant.sys.FormStatusConstant;
import com.plian.system.dto.im.FundProjectInfoDTO;
import com.plian.system.entity.im.FundInvestedProject;
import com.plian.system.entity.im.FundProject;
import com.plian.system.entity.im.FundProjectAmountDetail;
import com.plian.system.mapper.im.FundProjectMapper;
import com.plian.system.mybatis.base.BaseServiceImpl;
import com.plian.system.service.im.IFundInvestedProjectService;
import com.plian.system.service.im.IFundProjectAmountDetailService;
import com.plian.system.service.im.IFundProjectExecutionService;
import com.plian.system.service.im.IFundProjectService;
import com.plian.system.service.wf.FormWorkflowService;
import com.plian.system.vo.im.FundInvestedProjectVO;
import com.plian.system.vo.im.FundProjectExecutionVO;
import com.plian.system.vo.im.FundProjectVO;
import com.plian.system.wrapper.im.FundInvestedProjectWrapper;
import com.plian.system.wrapper.im.FundProjectWrapper;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * 服务实现类
 *
 * @author
 * @since 2019-09-27
 */
@Slf4j
@Service
@AllArgsConstructor
public class FundProjectServiceImpl extends BaseServiceImpl<FundProjectMapper, FundProject> implements IFundProjectService {

	private FormWorkflowService formWorkflowService;

	private IFundInvestedProjectService fundInvestedProjectService;

	private FundInvestedProjectWrapper fundInvestedProjectWrapper;

	private FundProjectWrapper fundProjectWrapper;

	private IFundProjectAmountDetailService fundProjectAmountDetailService;

	@Override
	public boolean saveOrUpdate(FundProject fundProject) {

		if (!Optional.ofNullable(fundProject.getStatus()).isPresent()) {
			fundProject.setStatus(FormStatusConstant.UNREVIEWED);
		}
		return super.saveOrUpdate(fundProject);
	}

	@Override
	@Transactional(rollbackFor=RuntimeException.class)
	public boolean deleteLogic(List<Long> ids) {
		for (Long id : ids) {
			FundProject fundProject = getById(id);
			if (fundProject == null) {
				return false;
			} else if (fundProject.getStatus() != null &&
					(fundProject.getStatus() != FormStatusConstant.STASH && fundProject.getStatus() != FormStatusConstant.UNREVIEWED)) {
				return false;
			}
			formWorkflowService.deleteProcessInstance(String.valueOf(id));
		}

		boolean result = super.deleteLogic(ids);
		if (result){
			fundInvestedProjectService.deleteByParentId(ids);
		}
		return result;
	}




	@Override
	public boolean submit(FundProject fundProject) {
		if (fundProject.getId() != null){
			fundProjectAmountDetailService.removeByBaseId(fundProject.getId());
		}
		boolean result = saveOrUpdate(fundProject);
		if (result){
			if (CollectionUtil.isNotEmpty(fundProject.getGpDetailList())){
				for (int i = 0; i < fundProject.getGpDetailList().size(); i++){
					FundProjectAmountDetail amountDetail = fundProject.getGpDetailList().get(i);
					amountDetail.setOrderNumber(i + 1);
					amountDetail.setAmountType(InvestmentConstant.GP_AMOUNT_DETAIL_TYPE);
					amountDetail.setFundProjectId(fundProject.getId());
					amountDetail.setId(null);
				}
				fundProjectAmountDetailService.saveBatch(fundProject.getGpDetailList());
			}
			if (CollectionUtil.isNotEmpty(fundProject.getLpDetailList())){
				for (int i = 0; i < fundProject.getLpDetailList().size(); i++){
					FundProjectAmountDetail amountDetail = fundProject.getLpDetailList().get(i);
					amountDetail.setOrderNumber(i + 1);
					amountDetail.setAmountType(InvestmentConstant.LP_AMOUNT_DETAIL_TYPE);
					amountDetail.setFundProjectId(fundProject.getId());
					amountDetail.setId(null);
				}
				fundProjectAmountDetailService.saveBatch(fundProject.getLpDetailList());
			}
			List<FundInvestedProject> fundInvestedProjects = fundProject.getFundInvestedProjects();
			if (CollectionUtil.isNotEmpty(fundInvestedProjects)){
				for (FundInvestedProject fundInvestedProject : fundInvestedProjects){
					if (fundInvestedProject.getId() != null &&
							Optional.ofNullable(fundInvestedProject.getIsDeleted()).isPresent() && fundInvestedProject.getIsDeleted().intValue() == 1) {
						fundInvestedProjectService.removeById(fundInvestedProject.getId());
					}else {
						fundInvestedProject.setFundProjectId(fundProject.getId());
						fundInvestedProjectService.saveOrUpdate(fundInvestedProject);
					}
				}
			}

		}

		return result;
	}

	@Override
	public List<FundProjectVO> getDetailPd(List<FundProjectVO> fundProjectVOS) {

		if(CollectionUtil.isEmpty(fundProjectVOS)){
			return new ArrayList<>();
		}
		Map<String, List<FundProjectAmountDetail>> amountDetailMap = fundProjectAmountDetailService
				.getMapByBaseIds(fundProjectVOS.stream().map(FundProjectVO::getId).collect(Collectors.toList()));
		for (FundProjectVO fundProjectVO : fundProjectVOS){
			fundProjectVO.setFundInvestedProjectVOS(fundInvestedProjectWrapper
					.entityToVO(fundInvestedProjectService.list(new LambdaQueryWrapper<FundInvestedProject>()
							.eq(FundInvestedProject::getFundProjectId, fundProjectVO.getId()))));
			fundProjectVO.setGpDetailList(amountDetailMap.get(fundProjectVO.getId() + StringPool.UNDERSCORE + InvestmentConstant.GP_AMOUNT_DETAIL_TYPE));
			fundProjectVO.setLpDetailList(amountDetailMap.get(fundProjectVO.getId() + StringPool.UNDERSCORE + InvestmentConstant.LP_AMOUNT_DETAIL_TYPE));
		}

		return fundProjectVOS;
	}

	@Override
	public List<FundProjectVO> getLastMonthInfos(List<FundProjectVO> fundProjectVOS) {
		if(CollectionUtil.isEmpty(fundProjectVOS)){
			return new ArrayList<>();
		}
		for (FundProjectVO fundProjectVO : fundProjectVOS){
			fundProjectVO.setBaseInvestmentExecutionId(null);
			fundProjectVO.setCreateUser(null);
			fundProjectVO.setCreateTime(null);
			fundProjectVO.setUpdateUser(null);
			fundProjectVO.setUpdateTime(null);
			List<FundInvestedProjectVO> fundInvestedProjectVOS = fundInvestedProjectWrapper
					.entityToVO(fundInvestedProjectService.list(new LambdaQueryWrapper<FundInvestedProject>()
							.eq(FundInvestedProject::getFundProjectId, fundProjectVO.getId())));
			if (CollectionUtil.isNotEmpty(fundInvestedProjectVOS)){
				for (FundInvestedProjectVO fundInvestedProjectVO : fundInvestedProjectVOS){
					fundInvestedProjectVO.setId(null);
					fundInvestedProjectVO.setFundProjectId(null);
					fundInvestedProjectVO.setCreateUser(null);
					fundInvestedProjectVO.setCreateTime(null);
					fundInvestedProjectVO.setUpdateUser(null);
					fundInvestedProjectVO.setUpdateTime(null);
				}
			}
			fundProjectVO.setFundInvestedProjectVOS(fundInvestedProjectVOS);
			fundProjectVO.setId(null);
		}

		return fundProjectVOS;
	}

	@Override
	public void write(List<FundProject> fundProjects, ExcelWriter excelWriter, WriteSheet writeSheet, FillConfig fillConfig) {
		/**
		 * 合计
		 */
		FundProjectExcelBean total = FundProjectExcelBean.builder().build();
		List<FundProjectExcelBean> fundProjectExcelBeans = new ArrayList<>();
		if (CollectionUtil.isNotEmpty(fundProjects)){
			List<FundProjectVO> fundProjectVOS = fundProjectWrapper.entityToVO(fundProjects);

			for (int i = 0; i < fundProjectVOS.size(); i++){
				FundProjectVO fundProject = fundProjectVOS.get(i);

				FundProjectExcelBean fundProjectExcelBean = new FundProjectExcelBean();
				BeanUtils.copyProperties(fundProject, fundProjectExcelBean);
				fundProjectExcelBean.setIndex(String.valueOf(i+1));
				//fundProjectExcelBean.setTimeStr(DateUtil.formatDate(fundProject.getStartTime()) + StringPool.DASH + DateUtil.formatDate(fundProject.getEndTime()));
				fundProjectExcelBeans.add(fundProjectExcelBean);
				// 合计
				//total.setGp(BigDecimalUtil.add(total.getGp(), fundProject.getGp()));
				//total.setLp(BigDecimalUtil.add(total.getLp(), fundProject.getLp()));
				total.setContributedCapital(BigDecimalUtil.add(total.getContributedCapital(), fundProject.getContributedCapital()));
				total.setCompanyContributedCapital(BigDecimalUtil.add(total.getCompanyContributedCapital(), fundProject.getCompanyContributedCapital()));
				total.setHasContributedCapital(BigDecimalUtil.add(total.getHasContributedCapital(), fundProject.getHasContributedCapital()));
				List<FundInvestedProject> fundInvestedProjects = fundInvestedProjectService
						.list(new LambdaQueryWrapper<FundInvestedProject>().eq(FundInvestedProject::getFundProjectId, fundProject.getId()));

				if (CollectionUtil.isNotEmpty(fundInvestedProjects)){
					boolean flag = false;
					for (FundInvestedProject fundInvestedProject : fundInvestedProjects){
						total.setInvestment(BigDecimalUtil.add(total.getInvestment(), (fundInvestedProject.getInvestment())));
						FundProjectExcelBean empty = new FundProjectExcelBean();
						//基金已投项目情况处理
						if (flag){
							empty.setProjectName(fundInvestedProject.getProjectName());
							empty.setInvestment(fundInvestedProject.getInvestment());
							empty.setListingProgress(fundInvestedProject.getListingProgress());
							empty.setEarnings(fundInvestedProject.getEarnings());
							empty.setFundInvestedYear(fundInvestedProject.getFundInvestedYear());
							fundProjectExcelBeans.add(empty);
						}else {
							fundProjectExcelBean.setProjectName(fundInvestedProject.getProjectName());
							fundProjectExcelBean.setInvestment(fundInvestedProject.getInvestment());
							fundProjectExcelBean.setListingProgress(fundInvestedProject.getListingProgress());
							fundProjectExcelBean.setEarnings(fundInvestedProject.getEarnings());
							fundProjectExcelBean.setFundInvestedYear(fundInvestedProject.getFundInvestedYear());
						}
						flag = true;
					}
				}
			}

		}
		excelWriter.fill(new FillWrapper("a", fundProjectExcelBeans), fillConfig, writeSheet);
		excelWriter.fill(total, fillConfig, writeSheet);
	}

	@Override
	public void writeVO(List<FundProjectVO> fundProjectVOS, ExcelWriter excelWriter, WriteSheet writeSheet, FillConfig fillConfig) {
		/**
		 * 合计
		 */
		FundProjectExcelBean total = FundProjectExcelBean.builder().build();
		List<FundProjectExcelBean> fundProjectExcelBeans = new ArrayList<>();
		for (int i = 0; i < fundProjectVOS.size(); i++){
			FundProjectVO fundProject = fundProjectVOS.get(i);
			String affiliatedOrgFullName=fundProject.getAffiliatedOrgFullName();
			FundProjectExcelBean fundProjectExcelBean = new FundProjectExcelBean();
			BeanUtils.copyProperties(fundProject, fundProjectExcelBean);
			if(!"合计".equals(affiliatedOrgFullName)){
				fundProjectExcelBean.setIndex(String.valueOf(i+1));
				fundProjectExcelBean.setStartTimeStr(DateUtil.formatDate(fundProject.getStartTime()));
				fundProjectExcelBean.setEndTimeStr(DateUtil.formatDate(fundProject.getEndTime()));
			}
			fundProjectExcelBeans.add(fundProjectExcelBean);
			// 合计
			total.setGp(BigDecimalUtil.add(total.getGp(), fundProject.getGp()));
			total.setLp(BigDecimalUtil.add(total.getLp(), fundProject.getLp()));
			total.setFundScale(BigDecimalUtil.add(total.getFundScale(), fundProject.getFundScale()));
			total.setSubscribedCapital(BigDecimalUtil.add(total.getSubscribedCapital(), fundProject.getSubscribedCapital()));
			total.setCompanyContributedCapital(BigDecimalUtil.add(total.getCompanyContributedCapital(), fundProject.getCompanyContributedCapital()));
			total.setContributedCapital(BigDecimalUtil.add(total.getContributedCapital(), fundProject.getContributedCapital()));
			total.setYearContributedCapital(BigDecimalUtil.add(total.getYearContributedCapital(), fundProject.getYearContributedCapital()));
			total.setHasContributedCapital(BigDecimalUtil.add(total.getHasContributedCapital(), fundProject.getHasContributedCapital()));
			total.setCompanyYearContributedCapital(BigDecimalUtil.add(total.getCompanyYearContributedCapital(), fundProject.getCompanyYearContributedCapital()));
			int maxIndex = 0;
			if (CollectionUtil.isNotEmpty(fundProject.getGpDetailList())){
				if (fundProject.getGpDetailList().size() > maxIndex){
					maxIndex = fundProject.getGpDetailList().size();
				}
			}

			if (CollectionUtil.isNotEmpty(fundProject.getLpDetailList())){
				if (fundProject.getLpDetailList().size() > maxIndex){
					maxIndex = fundProject.getLpDetailList().size();
				}
			}

			if (CollectionUtil.isNotEmpty(fundProject.getFundInvestedProjectVOS())){
				if (fundProject.getFundInvestedProjectVOS().size() > maxIndex){
					maxIndex = fundProject.getFundInvestedProjectVOS().size();
				}
			}

			for (int j = 0; j < maxIndex; j++){
				FundProjectExcelBean empty = fundProjectExcelBean;
				if (j > 0){
					empty = new FundProjectExcelBean();
					fundProjectExcelBeans.add(empty);
				}
				if (CollectionUtil.isNotEmpty(fundProject.getFundInvestedProjectVOS())
						&& fundProject.getFundInvestedProjectVOS().size() > j){
					FundInvestedProjectVO fundInvestedProjectVO = fundProject.getFundInvestedProjectVOS().get(j);
					empty.setProjectName(fundInvestedProjectVO.getProjectName());
					empty.setInvestment(fundInvestedProjectVO.getInvestment());
					empty.setListingProgress(fundInvestedProjectVO.getListingProgress());
					empty.setEarnings(fundInvestedProjectVO.getEarnings());
					empty.setFundInvestedYear(fundInvestedProjectVO.getFundInvestedYear());
				}

				if (CollectionUtil.isNotEmpty(fundProject.getGpDetailList())
						&& fundProject.getGpDetailList().size() > j){
					FundProjectAmountDetail fundProjectAmountDetail = fundProject.getGpDetailList().get(j);
					empty.setGpDetailCompanyName(fundProjectAmountDetail.getCompanyName());
					empty.setGpDetailAmount(fundProjectAmountDetail.getAmount());
				}

				if (CollectionUtil.isNotEmpty(fundProject.getLpDetailList())
						&& fundProject.getLpDetailList().size() > j){
					FundProjectAmountDetail fundProjectAmountDetail = fundProject.getLpDetailList().get(j);
					empty.setLpDetailCompanyName(fundProjectAmountDetail.getCompanyName());
					empty.setLpDetailAmount(fundProjectAmountDetail.getAmount());
				}
			}
		}
		excelWriter.fill(new FillWrapper("a", fundProjectExcelBeans), fillConfig, writeSheet);
	}

	@Override
	public boolean deleteByParentId(List<Long> ids) {
		LambdaQueryWrapper<FundProject> queryWrapper = new LambdaQueryWrapper<>();
		queryWrapper.in(FundProject::getBaseInvestmentExecutionId, ids);
		List<FundProject> fundProjects = list(queryWrapper);
		if (CollectionUtil.isNotEmpty(fundProjects)){
			return deleteLogic(fundProjects.stream().map(FundProject::getId).collect(Collectors.toList()));
		}
		return true;
	}

	@Override
	public void exportReport(List<FundProjectExecutionVO> fundProjectExecutionVOS, FundProjectInfoDTO fundProjectInfoDTO, HttpServletResponse response) {
		try{
			IFundProjectExecutionService fundProjectExecutionService= SpringUtil.getBean(IFundProjectExecutionService.class);
			List<FundProjectVO> list = fundProjectExecutionService.executionListDetail(fundProjectExecutionVOS,fundProjectInfoDTO);
			/**
			 * 导出路径不存在则创建
			 */
			String separator = File.separator;
			String exlPath = separator + "exceldemo" + separator + "fundProjectExecution.xlsx";
			InputStream inputStream = getClass().getClassLoader().getResourceAsStream(exlPath);//2024-12-23 换一种写法要不然获取不到路径
			String fileName = URLEncoder.encode("市属国企基金项目统计表", "UTF-8");
			response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");
			// 设置响应头和客户端保存文件名
			response.setCharacterEncoding("utf-8");
			OutputStream outputStream = response.getOutputStream();// 取得输出流
			ExcelWriter excelWriter = EasyExcel.write(outputStream).withTemplate(inputStream).build();
			// 这里注意 入参用了forceNewRow 代表在写入list的时候不管list下面有没有空行 都会创建一行，然后下面的数据往后移动。默认 是false，会直接使用下一行，如果没有则创建。
			// forceNewRow 如果设置了true,有个缺点 就是他会把所有的数据都放到内存了，所以慎用
			// 简单的说 如果你的模板有list,且list不是最后一行，下面还有数据需要填充 就必须设置 forceNewRow=true 但是这个就会把所有数据放到内存 会很耗内存

			FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build();

			//
			WriteSheet writeSheet = EasyExcel.writerSheet(0).build();

			writeVO(list,excelWriter,writeSheet,fillConfig);
			excelWriter.finish();
		}catch (Exception e){
			e.printStackTrace();
		}
	}


}
